﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;

namespace SharpCommon.Utility
{
    public class IdentifyingCode
    {
        private readonly string BlackFlag = "1";
        private readonly string WhiteFlag = "0";

        private readonly Dictionary<int, string> Values = new Dictionary<int, string>
        {
            {38, "0"},{19, "1"},{37, "2"},{52, "3"},{50, "4"},
            {35, "5"},{41, "6"},{28, "7"},{64, "8"},{42, "9"}
        };

        public static readonly IdentifyingCode Instance = new IdentifyingCode();

        private IdentifyingCode()
        {
        }

        public string Check(string filePath)
        {
            using (Bitmap bitmap = new Bitmap(filePath))
            {
                this.Gray(bitmap);
                this.Threshold(bitmap, 190);
                List<TempSize> tempSizes = this.Carve(bitmap);
                return this.GetValue(bitmap, tempSizes.ToArray());
            }
        }

        private void Gray(Bitmap bitmap)
        {
            for (int x = 0; x < bitmap.Width; x++)
            {
                for (int y = 0; y < bitmap.Height; y++)
                {
                    int grayNumber = GetGrayNumber(bitmap.GetPixel(x, y));
                    bitmap.SetPixel(x, y, Color.FromArgb(grayNumber, grayNumber, grayNumber));
                }
            }
        }

        private int GetGrayNumber(Color color)
        {
            return (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);
        }

        private void Threshold(Bitmap bitmap, int criticalValue)
        {
            for (int x = 0; x < bitmap.Width; x++)
            {
                for (int y = 0; y < bitmap.Height; y++)
                {
                    Color color = bitmap.GetPixel(x, y);
                    bitmap.SetPixel(x, y, color.R >= criticalValue ? Color.White : Color.Black);
                }
            }
        }

        private List<TempSize> Carve(Bitmap originalBitmap)
        {
            string blackPointFlags = GetBlackPointFlags(originalBitmap);

            bool flag = true;
            int xStart = default(int);
            List<TempSize> tempSizes = new List<TempSize>();

            for (int x = 0; x < originalBitmap.Width; x++)
            {
                if (blackPointFlags.Substring(x, 1) == BlackFlag)
                {
                    if (flag)
                    {
                        flag = false;
                        xStart = x;
                    }
                    if (x < originalBitmap.Width)
                    {
                        if (blackPointFlags.Substring(x + 1, 1) == WhiteFlag)
                        {
                            int xEnd = x;
                            TempSize tempSize = new TempSize
                            {
                                XStart = xStart,
                                XWidth = (xEnd - xStart) + 1
                            };
                            tempSizes.Add(tempSize);
                        }
                    }
                }
                else
                {
                    flag = true; //重新开始
                }
            }
            return tempSizes;
        }

        private string GetBlackPointFlags(Bitmap originalBitmap)
        {
            string everyColumnHasBlackPoints = string.Empty;

            for (int x = 0; x < originalBitmap.Width; x++)
            {
                for (int y = 0; y < originalBitmap.Height; y++)
                {
                    if (originalBitmap.GetPixel(x, y).R == Color.Black.R)
                    {
                        everyColumnHasBlackPoints += "1";
                        break;
                    }
                }
                if (everyColumnHasBlackPoints.Length != x + 1)
                {
                    everyColumnHasBlackPoints += "0";
                }
            }
            return everyColumnHasBlackPoints;
        }

        private string GetValue(Bitmap originalBitmap, TempSize[] tempSizes)
        {
            string result = string.Empty;
            for (int index = 0; index < tempSizes.Length; index++)
            {
                string pointValues = string.Empty;
                TempSize tempSize = tempSizes[index];
                for (int x = tempSize.XStart; x < tempSize.XStart + tempSize.XWidth; x++)
                {
                    for (int y = 0; y < originalBitmap.Height; y++)
                    {
                        var color = originalBitmap.GetPixel(x, y);
                        pointValues += color.R == 0 ? "1" : "0";
                    }
                }

                int blackPointCount = pointValues.Count(p => p == '1');
                if (this.Values.ContainsKey(blackPointCount))
                {
                    result += this.Values[blackPointCount];
                }
            }
            return result;
        }
    }

    public struct TempSize
    {
        public int XStart;
        public int XWidth;
        public int Y;
    }
}
